# -*- coding: utf-8 -*-
# @Time    : 2016/9/28
from sympy import solve, Eq, sympify
from mathsolver.functions.base.base import BaseFunction, new_latex
from mathsolver.functions.base.objects import BaseFunc, BaseEq, BaseSymbolValue, BasePoint, BaseIneqs, BaseSinFunc
from mathsolver.functions.daoshu.qiexianxielu import DaoShuQieXianXieLv001
from mathsolver.functions.zhixian.property import GetXieLv001, GetZhiXianYiBanShi, GetZhiXianCoeff
from mathsolver.functions.hanshu.helper import check_func, solveset


class QieXianFangChengQiuCan001(BaseFunction):
    """
    已知切线方程求参数——切点已知
    """
    def solver(self, *args):
        func, point, eq = args
        func = check_func(func)
        x1, x2 = point.sympify()

        # 求切线的斜率
        qiuxielu = DaoShuQieXianXieLv001().solver(func, point)
        xielu = qiuxielu.output[0]
        self.steps.extend(qiuxielu.steps)

        # 由直线方程观察得到直线斜率
        step1 = GetZhiXianYiBanShi().solver(eq).output[0]
        step2 = GetZhiXianCoeff().solver(step1).output[0]
        qiuxielu2 = GetXieLv001().solver(step2)

        xielu2 = qiuxielu2.output[0]
        self.steps.append(["根据切线方程 {} 得斜率为 {}".format(eq.printing(), xielu2.printing()), ""])

        # 切线斜率和利用导数求得的切线斜率相等；将切点坐标分别代入切线和曲线方程
        eq1 = Eq(xielu.sympify(), xielu2.sympify())

        # 如果x2的值没有给定，需要先求出x2的值
        if x2.is_Function:
            l, r = eq.sympify()
            x2 = solve((l - r).subs(func.var, x1))[0]

        eq2 = Eq(func.expression.subs(func.var, x1), x2)

        # 补充：如果含有多于2个参数，返回方程组
        eq_symbols = eq1.free_symbols.union(eq2.free_symbols)
        if len(eq_symbols) > 3:
            self.output.append(BaseIneqs([eq1.args, eq2.args]))
            return self

        # 联立方程求得未知数
        result = solveset([eq1, eq2], dict=True)
        output_result = BaseSymbolValue(result)
        self.steps.append(["同时根据点在直线上：",
                           r"\left\{{\begin{{matrix}} {} & \\ {}  &  \end{{matrix}}\right."
                          .format(new_latex(eq1), new_latex(eq2))])
        self.steps.append(["", "解得 %s" % output_result.printing()])
        self.output.append(output_result)
        self.label.add("已知切线方程求参数")
        return self


def is_zhixian(baseinput):
    """判断输入是否是直线（可能是曲线 BaseEq(['*', '*']) ）"""
    return isinstance(baseinput, (BaseFunc, BaseSinFunc)) or sympify(baseinput.value[0]).is_Atom


class QieXianFangChengQiuCan002(BaseFunction):
    """已知切线方程求参数——切点未知"""

    def solver(self, *args):
        zhixian_yuanzhui_func, qiexian_func = args[0], check_func(args[1])

        # 补充：设置 index 的值，保证相邻的两次调用设出的切点不一样
        if 'qiexian_index' in self.known:
            index_old = self.known['qiexian_index']
            index = (index_old + 1) % 3
        else:
            index = 0
        self.known['qiexian_index'] = index

        # 设出切点坐标
        qiedian = BasePoint({'name': '', 'value': ['x%s' % index, 'y%s' % index]})
        x1, x2 = qiedian.sympify()
        self.steps.append(["设切点坐标为 {}".format(qiedian.printing()), ""])

        # 利用导数求切线斜率

        # 可能是圆锥曲线
        qiuxielu = DaoShuQieXianXieLv001().solver(zhixian_yuanzhui_func, qiedian)
        xielu = qiuxielu.output[0]
        self.steps.extend(qiuxielu.steps)

        # 已知直线方程求直线斜率
        qiexian_eq = BaseEq([qiexian_func.name, qiexian_func.expression])
        step1 = GetZhiXianYiBanShi().solver(qiexian_eq).output[0]
        step2 = GetZhiXianCoeff().solver(step1).output[0]
        qiuxielu2 = GetXieLv001().solver(step2)
        xielu2 = qiuxielu2.output[0]
        self.steps.append(["根据切线方程 {} 得直线的斜率为 {}".format(qiexian_eq.printing(), xielu2.printing()), ""])

        # 切线斜率和利用导数求得的切线斜率相等；将切点坐标分别代入切线和曲线方程
        eq1 = Eq(xielu.sympify(), xielu2.sympify())
        eq2 = Eq(qiexian_func.expression.subs(qiexian_func.var, x1), x2)

        if is_zhixian(zhixian_yuanzhui_func):
            func = check_func(zhixian_yuanzhui_func)
            eq3 = Eq(func.expression.subs(func.var, x1), x2)
        else:
            from sympy.abc import x, y
            yz_left_og, yz_right_og = sympify(zhixian_yuanzhui_func.value)
            to_subs = {x: x1, y: x2}
            eq3 = Eq(yz_left_og.subs(to_subs), yz_right_og.subs(to_subs))

        # 联立方程求得未知数
        self.label.add("已知切线方程求参数")
        self.steps.append(["同时根据切点在直线和切线上：",
                           "\\left\{{\\begin{{matrix}} {} & \\\\ {} & \\\\ {} &  \\end{{matrix}}\\right.".format(new_latex(eq1),
                                                                                                           new_latex(eq2),
                                                                                                           new_latex(eq3))])
        # 如果含有多于2个参数，返回方程组
        eq_symbols = eq1.free_symbols.union(eq2.free_symbols).union(eq3.free_symbols)
        if len(eq_symbols) > 3:
            self.output.append(BaseIneqs([eq1.args, eq2.args, eq3.args]))
            return self

        result = solveset([eq1, eq2, eq3], dict=True)
        output_result = BaseSymbolValue(result)
        # self.steps.append(["解得 " + ", ".join(["{} = {}".format(key, value) for key, value in result.items()]), ""])
        self.steps.append(["", "解得：%s" % output_result.printing()])
        # self.output.append(BaseSymbolValue({tuple(result.keys()): [tuple(result.values())]}))
        self.output.append(output_result)
        return self


if __name__ == '__main__':
    pass
